/*
 * @Overview     : vue.config
 * @Author       : Zi Jun
 * @Email        : zijun2030@163.com
 * @Date         : 2020-12-23 19:28:52
 * @LastEditTime : 2021-02-18 09:21:08
 * @LastEditors  : Zi Jun
 * @FilePath     : \simple-vue\vue.config.js
 * @Mark         : 1. 配置路径别名
 *                 2. 配置全局样式
 *                 3. CDN优化，后续可根据添加依赖选择性CDN或splitChunk处理
 *                 4. 代码分割优化
 *                 5. 生产去除console
 */

/* 环境变量 */
const {
  NODE_ENV,
  VUE_APP_PUBLIC_PATH,
  VUE_APP_PORT,
  VUE_APP_PROXY,
  VUE_APP_OUTPUT_DIR,
  VUE_APP_DROP_CONSOLE,
} = process.env;

/* CDN */
const CDN = {
  // 外链接(忽略打包的第三方库)，在index.html引入对应外链接
  externals: {
    vue: 'Vue',
    vuex: 'Vuex',
    'vue-router': 'VueRouter',
    axios: 'axios',
    vant: 'vant',
    dayjs: 'dayjs',
    'vue-i18n': 'VueI18n',
    vconsole: 'VConsole',
  },
  // 通过cdn使用,注意应尽量与package中dependencies版本号保持一致
  js: [
    'https://cdn.jsdelivr.net/npm/vue@3.0.5/dist/vue.global.min.js',
    'https://cdn.jsdelivr.net/npm/vue-router@4.0.3/dist/vue-router.global.min.js',
    'https://cdn.jsdelivr.net/npm/vuex@4.0.0/dist/vuex.global.min.js',
    'https://cdn.jsdelivr.net/npm/vant@next/lib/vant.min.js',
    'https://cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js',
    'https://cdn.jsdelivr.net/npm/dayjs@1.10.4/dayjs.min.js',
    'https://cdn.jsdelivr.net/npm/vue-i18n@9.0.0-rc.7/dist/vue-i18n.global.min.js',
    'https://cdn.jsdelivr.net/npm/vconsole@3.4.0/dist/vconsole.min.js',
  ],
  css: [],
};

/* Gzip插件，注意版本控制，测试 7.x.x会报错，故采用6.x.x版本 */
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i;

/* JS压缩插件, cli4已集成terserPlugin插件 */
/* 打包文件分析 */
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

/* 路径方法 */
const path = require('path');
const resolve = (dir) => path.join(__dirname, dir);

/* 代理方法,用户开发API代理 */
const createProxy = (list) => {
  const result = {};
  for (const [prefix, target] of list) {
    result[prefix] = {
      target,
      changeOrigin: true,
      pathRewrite: { [`^${prefix}`]: '' },
    };
  }
  return result;
};

/* 生产环境判断 */
const isProduction = ['production', 'prod'].includes(NODE_ENV);

/***** 开发相关配置 *****/
const devServer = {
  host: require('./src/utils/get-ip.ts'),
  port: VUE_APP_PORT,
  open: true,
  https: false,
  compress: false,
  disableHostCheck: true,
  overlay: {
    warnings: true,
    errors: true,
  },
};
// 配置方向代理
if (VUE_APP_PROXY) {
  devServer.proxy = createProxy(eval(VUE_APP_PROXY));
}

const config = {
  /***** 基本配置 *****/
  // 资源全局路径前缀
  publicPath: VUE_APP_PUBLIC_PATH,
  // 输出文件目录
  outputDir: VUE_APP_OUTPUT_DIR,
  // eslint检测 默认是开启的
  lintOnSave: true,
  // 打包时不生成.map文件
  productionSourceMap: false,
  // 是否使用包含运行时编译器的 Vue 构建版本
  runtimeCompiler: true,
  parallel: require('os').cpus().length > 1,
  /***** 开发相关配置 *****/
  devServer,
  /***** webpack简单配置 *****/
  configureWebpack: {
    // 分包优化，如果chunk-vendor过大，则需cdn处理，cdn不了则需分包优化
    optimization: {
      runtimeChunk: 'single',
      splitChunks: {
        chunks: 'all',
        maxInitialRequests: Infinity,
        minSize: 1000 * 60,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name(module) {
              // 排除node_modules 然后吧 @ 替换为空 ,考虑到服务器的兼容
              const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
              return `npm.${packageName.replace('@', '')}`;
            },
          },
        },
      },
    },
  },
  /***** webpack链式操作 *****/
  chainWebpack: (config) => {
    // 修复HMR
    config.resolve.symlinks(true);
    // 设置路径别名
    config.resolve.alias.set('@', resolve('src'));
    // 移除资源预加载(路由懒加载才能正常使用)
    config.plugins.delete('preload').delete('prefetch');
    // 添加svg配置
    config.module.rule('svg').exclude.add(resolve('src/assets/svg')).end();
    const svgRule = config.module.rule('icons');
    svgRule.uses.clear();
    svgRule.include.add(resolve('src/assets/svg'));
    svgRule
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]',
      })
      .end();
    // 生产构建优化
    if (isProduction) {
      // 忽略打包配置
      config.externals(CDN.externals);
      // webpack会默认给commonChunk打进chunk-vendors，所以需要对webpack的配置进行delete
      config.optimization.delete('splitChunks');
      // 配置CDN引入,需要在index.html中导入
      config.plugin('html').tap((args) => {
        args[0].cdn = CDN;
        args[0].minify.minifyCSS = true;
        // 修复 Lazy loading routes Error
        args[0].chunksSortMode = 'none';
        return args;
      });
      // 移除调试信息
      config.optimization.minimizer('terser').tap((args) => {
        const option = args[0].terserOptions.compress;
        option.drop_console = eval(VUE_APP_DROP_CONSOLE);
        option.drop_debugger = true;
        option.pure_funcs = ['console.*'];
        args[0].terserOptions.output = {
          comments: false,
        };
        return args;
      });
      // Gzip压缩,启用后构建后会产生gz文件
      config.plugin('compressionPlugin').use(
        new CompressionWebpackPlugin({
          filename: '[path][base].gz',
          algorithm: 'gzip',
          test: productionGzipExtensions,
          threshold: 10240,
          minRatio: 0.8,
          deleteOriginalAssets: false,
        }),
      );
      // 打包分析，正式构建后会打开新页面查看
      config.plugin('webpack-bundle-analyzer').use(BundleAnalyzerPlugin);
    }
  },
  /***** 全局css *****/
  css: {
    // extract: 是否使用css分离插件，false为不为单独文件
    // extract: false,
    loaderOptions: {
      less: {
        lessOptions: {
          modifyVars: {
            hack: `true; @import "@/styles/global/index.less";`,
          },
        },
      },
    },
  },
};

module.exports = config;
